#!/usr/bin/env bash

include "libs/ohos.sh"
include "libs/output.sh"
include "libs/test.sh"

#help.cmd utils@dailybuild : (仓库) 以DailyBuild的方式编译打包
dynamic_cmd:utils:dailybuild()
{
    OHOS_WINDOW_USE=false

    dynamic_cmd:repo_sync || report "DailyBuild同步代码失败" || return

    OHOS_REMOVE_OUT=1
    OHOS_WINDOW_USE=true
    dynamic_cmd:cc_hosp || report "DailyBuild编译失败" || return

    OHOS_IMAGE_NAME="DB-Hi3516DV300-\$(date +\"%Y-%m-%d_%H-%M-%S\")"
    dynamic_cmd:utils:image || report "DailyBuild镜像打包失败" || return
    report "DailyBuild成功"
}

#help.cmd utils@image : (仓库) 打包镜像为OHOS_IMAGE_NAME放在OHOS_IMAGE_DIR下
dynamic_cmd:utils:image()
{
    ohos:cd_repo || return
    cd $OHOS_OUT_DIR/packages/phone/images || report "镜像打包失败" || return

    local name=$(eval echo $OHOS_IMAGE_NAME).tar.gz
    echo "打包中..."
    tar acf $name * || report "镜像打包失败" || return
    mv $name $OHOS_IMAGE_DIR || report "镜像打包失败" || return
#    mv $name /home/ts/文档/VMwareShare/image || report "镜像打包失败" || return
    [ $? = 0 ] && report "镜像打包成功，位于 $OHOS_IMAGE_DIR/$name"
}

#help.cmd utils@out : (仓库) 在out/ohos-arm-release下启动bash，用于反复编译
dynamic_cmd:utils:out()
{
    ohos:cd_repo || return
    cd $OHOS_OUT_DIR
    bash
}

#help.cmd utils@asm : (仓库) 反汇编
dynamic_cmd:utils:asm()
{
    local objdump="${OHOS_BINUTILS}objdump"

    ohos:cd_repo || return
    local result=$(find $OHOS_OUT_DIR/ -name "$FILE" -type f | grep unstripped | head -1)
    $objdump -d $result
}

#help.cmd utils@stack : (仓库) 打印Crash堆栈对应的文件堆栈
#alias.cmd ous : utils@stack
dynamic_cmd:utils:stack()
{
    ohos:cd_repo || return
    local addr2line="${OHOS_BINUTILS}addr2line"

    echo "请输入Crash堆栈(空行Ctrl+D结束输入):"
    stack_parser

    echo -e "\n查找结果是:"
    for ((i = $_STACK_PARSER_NEXTID - 1; i >= 0; i--)); do
        local addr=${_STACK_PARSER_ADDRS[$i]}
        local file=${_STACK_PARSER_FILES[$i]}

        local result=$(find $OHOS_OUT_DIR/ -name "$file" -type f | grep unstripped | head -1)
        ([ "$result" = "" ] || [ "$addr" = "" ]) && continue

        xresult="$($addr2line -e "$result" "$addr" | sed "s/.*\.\.\///g" | sed "s/:/ +/g" | sed "s/\/std\///g")"
        local source_file="$(echo $xresult | awk '{print $1}')"
        local source_line="$(echo $xresult | awk '{print $2}')"

        local filehl="g"
        local linehl="y"
        printf "* $(cctl c)$((i+1)) $(cctl $filehl)$source_file $(cctl r)$source_line from ${addr}$(cctl 0)\n"
        if [ -e "$source_file" ] && [ "$source_line" != "+?" ]; then
            local max=1
            origin_source_line=${source_line:1}
            source_line=$((max > ${source_line:1} - 5 ? max : ${source_line:1} - 5))

            cat -n "$source_file" |
                sed -n "$source_line,$((source_line+10))p" |
                sed "s/^\(\s*[0-9]*\)\t/$(cctl $linehl)*\1|$(cctl 0) /g" |
                sed "s/\t/$(cctl 777777)\\\\t->->->$(cctl 0)/g" |
                sed "s/\*\(\s*$origin_source_line|\)/$(cctl bg444444)>\1$(cctl 0)/g"
        fi
    done
}

_STACK_PARSER_NEXTID=0
_STACK_PARSER_ADDRS=()
_STACK_PARSER_FILES=()
function stack_parser()
{
    _STACK_PARSER_NEXTID=0
    _STACK_PARSER_ADDRS=()
    _STACK_PARSER_FILES=()

    local input="$(cat)"
    if [[ "$input" =~ (sf.AddrPC) ]]; then
        input="$(grep "sf.AddrPC" <<< "$input")"
        input="$(awk '{print $NF}' <<< "$input")"
        for addr in $input; do
            if ! [[ "$addr" =~ (^0x) ]]; then
                addr="0x$addr"
            fi
            _STACK_PARSER_ADDRS+=($addr)
            if [[ "$addr" =~ (^(0x)?0*18[0-9a-fA-F]{7}$) ]]; then
                file="libace_engine_windows.dll"
            else
                file=""
            fi
            _STACK_PARSER_FILES+=("$file")
            (( _STACK_PARSER_NEXTID++ ))
        done
    else
        input="$(grep "#" <<< "$input")"
        input="$(cut -d '#' -f 2- <<< "$input")"
        input="$(sed 's|\w* \w* 0*\([^(]*\)[()0-9a-f]* \([^(]*\).*|\1@\2|g' <<< "$input")"
        for addr_file in $input; do
            addr="0x${addr_file//@*/}"
            file="${addr_file//*@/}"
            file="${file//*\//}"
            _STACK_PARSER_ADDRS+=($addr)
            _STACK_PARSER_FILES+=($file)
            (( _STACK_PARSER_NEXTID++ ))
        done
    fi
}

function stack_parser::test()
{
    echo ""
    local win_crash='
        [2022-03-22T16:59:59.303] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]Engine Crash Info Begin.
        [2022-03-22T16:59:59.303] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]Address: 0x7ff821b590b0
        [2022-03-22T16:59:59.303] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]ErrorCode: 0xc0000005
        [2022-03-22T16:59:59.321] [INFO] default - [phone][203284][Engine Log][DEBUG]:[2022-03-22T16:59:59.321]Engine Websocket protocol init
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x7ff821b590b0
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x180f2acd6
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x180f179d3
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x180337016
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x1809ad1f7
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x1809ad0fc
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x1809a7b18
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x14001c11c
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x14001be39
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x140001b19
        [2022-03-22T16:59:59.442] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x14000296a
        [2022-03-22T16:59:59.443] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x1400013fa
        [2022-03-22T16:59:59.443] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x14000145b
        [2022-03-22T16:59:59.443] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x7ff821a37034
        [2022-03-22T16:59:59.443] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]sf.AddrPC.Offset : 0x7ff821b82651
        [2022-03-22T16:59:59.444] [INFO] default - [phone][203284][Engine Log][JsEngine Crash]Engine Crash Info End.
    '
    stack_parser <<< "$win_crash"
    for ((i = 0; i < _STACK_PARSER_NEXTID; i++)); do
        echo "addr: ${_STACK_PARSER_ADDRS[$i]}, file: ${_STACK_PARSER_FILES[$i]}"
    done

    echo ""
    local ohos_crash='
        #01 pc 0000000000006951(00000000b64d4951) /system/lib/libivi-shell.z.so(ivi_layout_surface_destroy+31)
        #02 pc 0000000000019ff1(00000000b5ba6ff1) /system/lib/libwmserver.z.so(wet_module_init+15747)
        #03 pc 0000000000019c1b(00000000b5ba6c1b) /system/lib/libwmserver.z.so(wet_module_init+14765)
        #04 pc 0000000000036f93(00000000b6df3f93) /system/lib/libweston.z.so(weston_surface_destroy+33)
    '
    stack_parser <<< "$ohos_crash"
    for ((i = 0; i < _STACK_PARSER_NEXTID; i++)); do
        echo "addr: ${_STACK_PARSER_ADDRS[$i]}, file: ${_STACK_PARSER_FILES[$i]}"
    done
}
# test:register_test stack_parser::test

#help.cmd utils@flush [tar.gz] : (仓库) 烧写板子 (目前只支持rk3568)
#alias.cmd ouf : utils@flush
dynamic_cmd:utils:flush()
{
    ohos:check_param OHOS_TOOL || return

    if [ "$1" != "" ]; then
        local targz="$1"
        if ! [[ "$(file "${targz}")" =~ (compressed) ]]; then
            output:loge "${targz}不是压缩文件，不能用来烧写"
            return 1
        fi
    fi

    if ! [ -d $OHOS_TOOL/repos/hihope_iot/.git ]; then
        mkdir -p $OHOS_TOOL/repos
        pushd $OHOS_TOOL/repos >/dev/null 2>&1
        output:logd "git cloning https://gitee.com/hihope_iot/docs"
        if git clone git@gitee.com:hihope_iot/docs hihope_iot; then
            output:logi "git clone success"
        else
            rm -rf hihope_iot
            output:loge "git clone failed"
            return 1
        fi
        popd >/dev/null 2>&1
    fi

    local image_path
    if [ "$targz" != "" ]; then
        image_path="/tmp/img"
        rm -rf "$image_path"
        mkdir "$image_path"

        output:logd "uncompressing"
        if tar axf "$targz" --directory="$image_path"; then
            output:logi "uncompress success"
        else
            output:loge "uncompress failed"
        fi
    else
        ohos:cd_repo || return
        image_path="$OHOS_OUT_DIR/packages/phone/images"
    fi

    local PYTHON="python"
    if which python3 >/dev/null 2>&1; then
        PYTHON="python3"
    fi

    local flush_python_path="$OHOS_TOOL/repos/hihope_iot/HiHope_DAYU200/烧写工具及指南/linux/flash.py"
    output:logd "flushing"
    if sudo -E $PYTHON "$flush_python_path" --image "$image_path" --all; then
        output:logi "flush success"
        sudo rm -rf $OHOS_TOOL/repos/hihope_iot/HiHope_DAYU200/烧写工具及指南/linux/bin/log
    else
        output:loge "flush failed"
    fi

    if [ "$targz" != "" ]; then
        rm -rf "$image_path"
    fi
}
